Skip to content

feat: improve mui components#215

Merged
smarcet merged 1 commit intoOpenStackweb:mainfrom
priscila-moneo:feature/improve-mui-components
Apr 9, 2026
Merged

feat: improve mui components#215
smarcet merged 1 commit intoOpenStackweb:mainfrom
priscila-moneo:feature/improve-mui-components

Conversation

@priscila-moneo
Copy link
Copy Markdown
Contributor

@priscila-moneo priscila-moneo commented Apr 9, 2026

ref: https://app.clickup.com/t/86b8t9qw1

Components: SnackbarNotification, DropdownCheckbox.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed snackbar notification closure when no message content is present.
    • Improved dropdown checkbox selection parsing and "all" option toggle behavior for better accuracy.
  • Enhancements

    • Dropdown checkbox component now supports additional configuration props for greater flexibility.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

This PR introduces a new empty() utility function for consistent empty value checking and refactors the SnackbarNotification component to use it for clearer intent. The DropdownCheckbox component is enhanced to accept and forward additional props while improving its selection value parsing logic.

Changes

Cohort / File(s) Summary
Utility Function
src/utils/methods.js
Added empty(value) utility that checks for null, undefined, whitespace-only strings, empty arrays, and empty objects.
Snackbar Refactoring
src/components/mui/SnackbarNotification/index.js
Replaced truthiness checks with empty() utility calls; updated visibility effect to explicitly close snackbar when content is empty; adjusted Redux sync effect to only update when content is not empty.
Dropdown Enhancements
src/components/mui/dropdown-checkbox.js
Added ...rest props forwarding to MUI Select component; refactored handleChange selection parsing to normalize values into arrays; extended "all" toggle logic with additional branch for explicit handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit hops through code so neat,
With empty() checks, the logic's sweet!
Props now flow where they belong,
And snackbars close when bits go wrong,
Selection parsing, clean and bright! 🌟

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'feat: improve mui components' is vague and overly broad. While it references the general area of changes (MUI components), it does not clearly convey the specific improvements made, such as the addition of an empty utility function, enhanced null/empty checking patterns, or the prop forwarding enhancements. Consider a more specific title such as 'feat: add empty utility and improve MUI component value handling' to better reflect the actual changes across SnackbarNotification, DropdownCheckbox, and the new utility function.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/utils/methods.js (1)

305-311: Consolidate emptiness helpers to avoid semantic drift.

Line 305 adds a second exported helper while isEmpty already exists (Line 213). Keeping both increases inconsistent usage risk; prefer one canonical helper name/behavior and migrate callers over time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/methods.js` around lines 305 - 311, The new exported helper empty
duplicates existing isEmpty causing inconsistent usage; replace the
implementation/export of empty with a canonical alias to isEmpty (or remove the
separate definition and export isEmpty only) so both names resolve to the same
logic; update the symbol references by changing the export of empty to reference
isEmpty (keeping a one-line alias export) or delete the empty function and
update callers to import isEmpty instead, and ensure only the isEmpty
implementation (the function at or around the existing isEmpty declaration)
remains as the single source of truth.
src/components/mui/dropdown-checkbox.js (1)

52-53: Consider collapsing duplicated "all" emission logic.

Line 53 sends the same payload as Line 46. You can reduce branching by emitting ["all"] once in a shared path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/dropdown-checkbox.js` around lines 52 - 53, The component
currently emits identical payloads of ["all"] in two branches; consolidate that
logic by calling onChange({ target: { name, value: ["all"] } }) from a single
shared path instead of duplicating it. Locate the handler using onChange and the
relevant variables name and value (e.g., inside the component's change handler
or function that processes selections) and refactor so both branches route to
the same "emit all" call (remove the duplicate call and ensure any
branch-specific cleanup happens before the shared emit).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/mui/dropdown-checkbox.js`:
- Around line 36-41: Normalize the types of items in selected when converting
ev.target.value so downstream comparisons like selected.includes(id) and
value.includes(id) match the option id types: after splitting the string
fallback, map the selected array to the same type as your option ids (e.g.
detect typeof options[0].id — if it's "number" convert numeric-looking strings
with Number(...) or parseInt, otherwise leave strings) so comparisons against id
work correctly; update the code that builds selected from ev.target.value (the
rawValue -> selected conversion) to perform this normalization.

In `@src/components/mui/SnackbarNotification/index.js`:
- Around line 63-65: The local state msgData isn't cleared when
snackbarMessage.html is reset to "", so update the handler around
snackbarMessage (the code using snackbarMessage?.html and setMsgData) to
synchronize clears: always call setMsgData(snackbarMessage) (or call
setMsgData(null) / {} in the else branch) when snackbarMessage becomes empty or
falsy so CLEAR_SNACKBAR_MESSAGE from Redux clears the local msgData; adjust the
effect or handler that reads snackbarMessage to setMsgData(snackbarMessage)
unconditionally or add an explicit else path to clear msgData.

---

Nitpick comments:
In `@src/components/mui/dropdown-checkbox.js`:
- Around line 52-53: The component currently emits identical payloads of ["all"]
in two branches; consolidate that logic by calling onChange({ target: { name,
value: ["all"] } }) from a single shared path instead of duplicating it. Locate
the handler using onChange and the relevant variables name and value (e.g.,
inside the component's change handler or function that processes selections) and
refactor so both branches route to the same "emit all" call (remove the
duplicate call and ensure any branch-specific cleanup happens before the shared
emit).

In `@src/utils/methods.js`:
- Around line 305-311: The new exported helper empty duplicates existing isEmpty
causing inconsistent usage; replace the implementation/export of empty with a
canonical alias to isEmpty (or remove the separate definition and export isEmpty
only) so both names resolve to the same logic; update the symbol references by
changing the export of empty to reference isEmpty (keeping a one-line alias
export) or delete the empty function and update callers to import isEmpty
instead, and ensure only the isEmpty implementation (the function at or around
the existing isEmpty declaration) remains as the single source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d7d23903-a655-442a-8370-8d820dc12ec0

📥 Commits

Reviewing files that changed from the base of the PR and between ecedf60 and 13585a6.

📒 Files selected for processing (3)
  • src/components/mui/SnackbarNotification/index.js
  • src/components/mui/dropdown-checkbox.js
  • src/utils/methods.js

Comment on lines +36 to +41
const rawValue = ev.target.value;
const selected = Array.isArray(rawValue)
? rawValue
: typeof rawValue === "string"
? rawValue.split(",")
: [];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In MUI v6 Select with multiple, when can event.target.value be a string, and what does MUI recommend for handling value types when option values are numbers?

💡 Result:

  • With Select multiple, event.target.value is only a string when the change is coming from browser autofill (otherwise it’s the normal “generic event” MUI fires, and the value you read is the array). MUI explicitly calls out that the onChange event is not a change event unless caused by autofill. [1] The type definition reflects this by allowing SelectChangeEvent to also be a React.ChangeEvent<HTMLInputElement> (whose target.value is a string). [2]

  • If your option values are numbers, MUI’s guidance implies you should handle the fact that selection matching is done via string representation (so types must stay consistent), and therefore you should convert the autofill string back into the numeric type you store (e.g., split and map(Number) for multiple). [1]

Sources: [1] Select API (onChange autofill note; value/string-representation matching), [2] SelectChangeEvent type (union including React.ChangeEvent<HTMLInputElement>)


🏁 Script executed:

cat -n src/components/mui/dropdown-checkbox.js | head -60

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2253


🏁 Script executed:

cat -n src/components/mui/dropdown-checkbox.js | tail -n +60

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 1535


🏁 Script executed:

rg "DropdownCheckbox" --type js --type tsx -B 2 -A 5 | head -80

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 111


🏁 Script executed:

rg "DropdownCheckbox" --type js -B 2 -A 5 | head -100

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 8121


🏁 Script executed:

cat -n src/components/mui/__tests__/dropdown-checkbox.test.js

Repository: OpenStackweb/openstack-uicore-foundation

Length of output: 2252


Normalize option ID types when converting ev.target.value in autofill scenarios.

When MUI Select fires onChange from browser autofill, ev.target.value is a string that must be split into an array. However, if option IDs are numeric, this creates a type mismatch: the selected array contains strings while the downstream checks at line 77 (selected.includes(id)) and line 89 (value.includes(id)) expect numeric types. This breaks both the rendered display and checked state after autofill.

Proposed fix
   const handleChange = (ev) => {
     const rawValue = ev.target.value;
-    const selected = Array.isArray(rawValue)
-      ? rawValue
-      : typeof rawValue === "string"
-      ? rawValue.split(",")
-      : [];
+    const selected = (Array.isArray(rawValue)
+      ? rawValue
+      : typeof rawValue === "string"
+      ? rawValue.split(",")
+      : []
+    ).map((v) => {
+      if (v === "all") return "all";
+      const match = options.find(({ id }) => String(id) === String(v));
+      return match ? match.id : v;
+    });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const rawValue = ev.target.value;
const selected = Array.isArray(rawValue)
? rawValue
: typeof rawValue === "string"
? rawValue.split(",")
: [];
const rawValue = ev.target.value;
const selected = (Array.isArray(rawValue)
? rawValue
: typeof rawValue === "string"
? rawValue.split(",")
: []
).map((v) => {
if (v === "all") return "all";
const match = options.find(({ id }) => String(id) === String(v));
return match ? match.id : v;
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/dropdown-checkbox.js` around lines 36 - 41, Normalize the
types of items in selected when converting ev.target.value so downstream
comparisons like selected.includes(id) and value.includes(id) match the option
id types: after splitting the string fallback, map the selected array to the
same type as your option ids (e.g. detect typeof options[0].id — if it's
"number" convert numeric-looking strings with Number(...) or parseInt, otherwise
leave strings) so comparisons against id work correctly; update the code that
builds selected from ev.target.value (the rawValue -> selected conversion) to
perform this normalization.

Comment on lines +63 to 65
if (!empty(snackbarMessage?.html)) {
setMsgData(snackbarMessage);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Redux clear events are no longer synced to local msgData.

Line 63 only updates local state when snackbarMessage?.html is non-empty. When CLEAR_SNACKBAR_MESSAGE resets html to "", local msgData is not cleared, so stale content can persist until another local action closes it.

🛠️ Proposed fix
  useEffect(() => {
    if (!empty(snackbarMessage?.html)) {
      setMsgData(snackbarMessage);
+    } else {
+      setMsgData({});
     }
  }, [snackbarMessage]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!empty(snackbarMessage?.html)) {
setMsgData(snackbarMessage);
}
if (!empty(snackbarMessage?.html)) {
setMsgData(snackbarMessage);
} else {
setMsgData({});
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/mui/SnackbarNotification/index.js` around lines 63 - 65, The
local state msgData isn't cleared when snackbarMessage.html is reset to "", so
update the handler around snackbarMessage (the code using snackbarMessage?.html
and setMsgData) to synchronize clears: always call setMsgData(snackbarMessage)
(or call setMsgData(null) / {} in the else branch) when snackbarMessage becomes
empty or falsy so CLEAR_SNACKBAR_MESSAGE from Redux clears the local msgData;
adjust the effect or handler that reads snackbarMessage to
setMsgData(snackbarMessage) unconditionally or add an explicit else path to
clear msgData.

@smarcet smarcet requested review from santipalenque and smarcet April 9, 2026 15:06
Copy link
Copy Markdown
Collaborator

@smarcet smarcet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Contributor

@santipalenque santipalenque left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@smarcet smarcet self-requested a review April 9, 2026 17:40
@smarcet smarcet merged commit 28b0d67 into OpenStackweb:main Apr 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants